package net.lb.io.json;

import java.util.Collection;
import java.util.Stack;
import net.lb.baseutil.collection.ObjectCollect;
import net.lb.baseutil.collection.StringCache;
import net.lb.io.json.util.JsonConfig;
import net.lb.io.json.util.JsonSerializer;

public class JsonUtil
{
    private static ThreadLocal<StringCache>   cacheLocal   = new ThreadLocal<StringCache>() {
                                                               protected StringCache initialValue()
                                                               {
                                                                   StringCache cache = new StringCache();
                                                                   return cache;
                                                               }
                                                           };
    private static ThreadLocal<ObjectCollect> collectLocal = new ThreadLocal<ObjectCollect>() {
                                                               protected ObjectCollect initialValue()
                                                               {
                                                                   return new ObjectCollect();
                                                               }
                                                           };
    
    public static void analyse(Class<?> type)
    {
        JsonConfig.getSerializer(type);
    }
    
    /**
     * 将一个javabean对象，转换成一个jsonobject或者是一个jsonarray
     * 
     * @param src
     * @return
     */
    public static Object fromObject(Object src)
    {
        ObjectCollect collect = new ObjectCollect();
        Class<?> type = src.getClass();
        JsonSerializer serializer = JsonConfig.getSerializer(type);
        return serializer.transToJsonvalue(src, collect);
    }
    
    /**
     * 将字符串转换成jsonobject或者是jsonarray
     * 
     * @param str
     * @return
     */
    public static Object fromString(String str)
    {
        Stack<Object> jsonStack = new Stack<>();
        Stack<String> keyStack = new Stack<>();
        // 可读信息标志位
        int flag = 0;
        // 当前读取位置
        int index = 0;
        int length = str.length();
        // 是否开始读取字符串
        boolean strStartRead = false;
        // 当前容器最上层是否是jsonobject，false代表是jsonarray
        boolean isObject = false;
        String jsonKey = null;
        while (index < length)
        {
            char c = str.charAt(index);
            // System.out.print(c);
            switch (c)
            {
                case '{':
                    jsonStack.push(new JsonObject());
                    isObject = true;
                    if (jsonKey != null)
                    {
                        keyStack.push(jsonKey);
                        jsonKey = null;
                        // 进入新的json，将计数器设置为0
                        flag = 0;
                    }
                    break;
                case '}':
                    // 如果计数器不为0，那就意味着还有非字符串形式的值尚未读取
                    if (flag != 0)
                    {
                        ((JsonObject) jsonStack.peek()).put(jsonKey, getNotStrValue(flag, index, str));
                        jsonKey = null;
                        flag = 0;
                    }
                    if (jsonStack.size() > 1)
                    {
                        JsonObject jsonObject = (JsonObject) jsonStack.pop();
                        Object ahead = jsonStack.peek();
                        if (ahead.getClass().equals(JsonObject.class))
                        {
                            ((JsonObject) ahead).put(keyStack.pop(), jsonObject);
                            isObject = true;
                        }
                        else
                        {
                            ((JsonArray) ahead).add(jsonObject);
                            isObject = false;
                        }
                    }
                    else
                    {
                        return jsonStack.pop();
                    }
                    break;
                case '[':
                    jsonStack.push(new JsonArray());
                    isObject = false;
                    if (jsonKey != null)
                    {
                        keyStack.push(jsonKey);
                        jsonKey = null;
                        flag = 0;
                        break;
                    }
                    flag = index + 1;
                    break;
                case ']':
                    if (flag != 0)
                    {
                        ((JsonArray) jsonStack.peek()).add(getNotStrValue(flag, index, str));
                        flag = 0;
                    }
                    if (jsonStack.size() > 1)
                    {
                        JsonArray jsonArray = (JsonArray) jsonStack.pop();
                        Object ahead = jsonStack.peek();
                        if (ahead.getClass().equals(JsonObject.class))
                        {
                            ((JsonObject) ahead).put(keyStack.pop(), jsonArray);
                            isObject = true;
                        }
                        else
                        {
                            ((JsonArray) ahead).add(jsonArray);
                            isObject = false;
                        }
                    }
                    else
                    {
                        return jsonStack.pop();
                    }
                    break;
                case '"':
                    if (strStartRead == false)
                    {
                        // 读取字符串的开始
                        flag = index + 1;
                        strStartRead = true;
                    }
                    else
                    {
                        if (isObject)
                        {
                            if (jsonKey == null)
                            {
                                jsonKey = str.substring(flag, index);
                            }
                            else
                            {
                                ((JsonObject) jsonStack.peek()).put(jsonKey, str.substring(flag, index));
                                jsonKey = null;
                            }
                        }
                        else
                        {
                            ((JsonArray) jsonStack.peek()).add(str.substring(flag, index));
                        }
                        flag = 0;
                        strStartRead = false;
                    }
                    break;
                case ':':
                    if (strStartRead)
                    {
                        break;
                    }
                    if (flag == 0)
                    {
                        flag = index + 1;
                    }
                    break;
                case ',':
                    if (strStartRead)
                    {
                        break;
                    }
                    if (flag != 0)
                    {
                        Object value = getNotStrValue(flag, index, str);
                        if (isObject)
                        {
                            ((JsonObject) jsonStack.peek()).put(jsonKey, value);
                            jsonKey = null;
                        }
                        else
                        {
                            ((JsonArray) jsonStack.peek()).add(value);
                        }
                        flag = 0;
                    }
                    break;
                default:
                    break;
            }
            index++;
        }
        throw new RuntimeException("json字符串存在错误");
    }
    
    private static Object getNotStrValue(int flag, int index, String str)
    {
        String tmp = str.substring(flag, index).trim();
        Object value = null;
        if (tmp.equals("true"))
        {
            value = Boolean.TRUE;
        }
        else if (tmp.equals("false"))
        {
            value = Boolean.FALSE;
        }
        else if (tmp.equals("null"))
        {
            value = null;
        }
        else if (tmp.contains("."))
        {
            value = Double.valueOf(tmp);
        }
        else if (tmp.equals("{"))
        {
            return null;
        }
        else
        {
            value = Long.valueOf(tmp);
        }
        return value;
    }
    
    /**
     * 将对象转换成json字符串或者json数组
     * 
     * @param object
     * @return
     */
    public static String toJsonString(Object object)
    {
        JsonSerializer serializer = JsonConfig.getSerializer(object.getClass());
        StringCache cache = cacheLocal.get();
        cache.clear();
        ObjectCollect collect = collectLocal.get();
        collect.clear();
        serializer.writeToString(cache, object, collect);
        return cache.toString();
    }
    
    public static String toString(Object src)
    {
        return toJsonString(src);
    }
    
    public static <T> T toBean(Object src, Class<T> t)
    {
        if (src.getClass().equals(String.class))
        {
            src = fromString((String) src);
        }
        return (T) JsonConfig.getSerializer(t).toBean(src, t);
    }
    
    /**
     * 将对象转换成一个collection对象。
     * 
     * @param src 需要转换的对象
     * @param collectionType collection对象的类别
     * @param paramType 参数类的类别
     * @return
     */
    public static Object toCollectionBean(Object src, Class<?> collectionType, Class<?> paramType)
    {
        try
        {
            if (src.getClass().equals(String.class))
            {
                src = fromString((String) src);
            }
            Collection<Object> collection = (Collection<Object>) collectionType.newInstance();
            JsonArray jsonArray = (JsonArray) fromObject(src);
            JsonSerializer serializer = JsonConfig.getSerializer(paramType);
            for (Object each : jsonArray)
            {
                collection.add(serializer.toBean(each, paramType));
            }
            return collection;
        }
        catch (InstantiationException | IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
    }
}
